<?php

/**
 * ����� ��� ��������� ��������, ����� �������������� � �������
 *
 * @version 1.03
 */
class FormValidator{
	
	public function __construct(){
		
		if(sizeof($_FILES) > 0){
			$_POST = array_merge($_POST, $_FILES);
		}
		
	}
	
	protected $errors = array();
	/**
	 * ������ �������� �����������
	 *
	 * @var array
	 */
	protected $validators=array();
	/**
	 * ������ �������� ��� ������ ��� ������ ���������
	 * 
	 * ������: ���_�������_��������� => �����; � ����������� {0}[{1}][{n}] ���������� �������� ������������ �������.
	 *
	 * @var array
	 */
	public static $valid_labels=array(	
		'NotEmptyTrim'=>"Поле не может быть пустым.\n",
		'LessThan'=>"Поле должно быть меньше {0}.\n",
		'MoreThan'=>"поле должно быть больше {0}.\n",
		'RegExp'=>"Неверный ввод.\n",
		'IsNumeric'=>"Поле должно быть цифрой.\n",
		'IsURL'=>"Поле должно содержать URL с указанием протокола http или https.\n",
		'IsInt'=>"Поле должно быть целым числом.\n",
		'IsDate'=>"Поле должно быть датой. Формат {0}\n",
		'IsImage'=>"Поле должно быть изображением.\n",
		'IsImageInternal'=>array(
			'file_not_found' => ' Файл не найден',
			'extension' => ' Некорректное расширение файла',
			'filesize' => ' Некорректный размер файла',
			'notimg' => ' Файл не является изображением.',
			'width' => ' Некорректная ширина',
			'height' => ' Некорректная высота',
			),
		'IsFile'=>"Поле должно быть корректным файлом.\n",			
		'IsFileInternal'=>array(
			'file_not_found' => ' Файл не найден',
			'extension' => ' Некорректное расширение файла',
			'filesize' => ' Некорректный размер файла',
			'notimg' => ' Файл не является изображением.',
			'width' => ' Некорректная ширина',
			'height' => ' Некорректная высота',
			),
		'IsEmail'=>"Ошибочный ввод Email.\n",
		);
	
	/**
	 * ������� ������� ��������� ����� ��������� ����� AddValidator
	 *
	 * ��������� ������ ����� ��� ��������.
	 * 
	 * @param array $vars
	 * @param array $validate_labels
	 * @return boolean
	 */
	public function ValidateFields(&$vars, $validate_labels=null){
		$validation=(sizeof($this->errors) == 0)?true:false;
		
		if(!is_array($validate_labels))$validate_labels=FormValidator::$valid_labels;
		
		foreach ($this->validators as $fieldName=>$curValid){
			if(!isset($vars[$fieldName])){
				$vars[$fieldName] = null;
			}
			if(is_array($curValid)){
				
				foreach ($curValid as $vName=>$value) {

					if(!is_array($value)){
						if($vName == 'MayBeEmpty'){
							if($this->$vName($vars[$fieldName], $value)){
								unset($this->errors[$fieldName]);
							}
						}
						elseif(!$this->$vName($vars[$fieldName], $value)){
							$validation=false;
							$this->errors[$fieldName][]=(isset($validate_labels[$vName]))?$this->_ParseLabel($validate_labels[$vName], $value):$vName;							
						}						
					}
					else {
						
						if($vName == 'MayBeEmpty'){
							if($this->$vName($vars[$fieldName], $value)){
								unset($this->errors[$fieldName]);
							}
						}
						
						if(sizeof($value)==1){
							if(!$this->$vName($vars[$fieldName], $value[0])){
								$validation=false;
								$this->errors[$fieldName][]=(isset($validate_labels[$vName]))?$this->_ParseLabel($validate_labels[$vName], $value):$vName;
							}							
						}
						elseif (sizeof($value)==2){
							if(!$this->$vName($vars[$fieldName], $value[0], $value[1])){
								$validation=false;
								$this->errors[$fieldName][]=(isset($validate_labels[$vName]))?$this->_ParseLabel($validate_labels[$vName], $value):$vName;
							}
						}
						
						elseif (sizeof($value)==3){
							if(!$this->$vName($vars[$fieldName], $value[0], $value[1], $value[2])){
								$validation=false;
								$this->errors[$fieldName][]=(isset($validate_labels[$vName]))?$this->_ParseLabel($validate_labels[$vName], $value):$vName;
							}
						}
					}				
					
				}
				
			}
			
		}
		
		if(is_array($this->errors) && sizeof($this->errors) == 0){
			$validation = true;
		}
		return $validation;
	}
	/**
	 * ���������� ������ �������� ����������� ����� ����� �������� ����� ValidateFields
	 *
	 * @return array|null
	 */
	public function GetErrorFields(){
		return $this->errors;
	}
	/**
	 * ��������� ������� �������� ������������� ����
	 * ����� ��������� ������� ���-�� ����� ��� �����������, ��������� ���� ������ � ������ params
	 * ����� ���������� ����� $ogj->AddValidate()->AddValidate()...->AddValidate();
	 *
	 * @param string $field_name
	 * @param string $validator
	 * @param mixed $params
	 * @return $this
	 */
	public function AddValidator($field_name, $validator, $params=null){
		
		$args=func_get_args();
		if(sizeof($args) > 3){
			
			for ($i=2; $i < sizeof($args); $i++){
				$params_new[]=$args[$i];
			}
			$params=$params_new;
		}
		
		if(method_exists($this, $validator)){
			$this->validators[$field_name][$validator]=$params;
						
			return $this;
		}
		else {
			throw new Exception("Method {$validator} does not exisits in ".__FILE__.':'.__LINE__);
		}		
		
	}
	
	/**
	 * ������� ������������� ������ ��� ������������� ��������
	 *
	 * @param string $field_name
	 * @param string $msg
	 * @return this
	 */
	public function AddError($field_name, $msg){
		
		$this->errors[$field_name][]=$msg;
		return $this;
		
	}
	/**
	 * ��������� ������������� �������
	 *
	 * @param string $name
	 * @param Array $arguments
	 * @return boolean
	 */
	public function __call($name, $arguments){
		
		$field_name=($arguments[1]!='')?$arguments[1]:'unknown';
		
		$this->errors[$field_name].="Validation failed. Method {$name} does not exists.";
		return false;
		
	}
	/**
	 * �������� ��� �������� ������ ���
	 *
	 * ��������� ������, ����� ��� �����. �� ���� ���������� ������� ������ false
	 * 
	 * @param mixed $vars
	 * @param numeric $value
	 * @param boolean $equal
	 * @return boolean
	 */
	static function LessThan(&$vars, $value, $equal=false){
		
		$value=(int)$value;
		
		if($equal){
			
			if(is_numeric($vars)){
				return ($vars <= $value)?true:false;
			}
			elseif (is_string($vars)){
				return (strlen($vars) <= $value)?true:false;
			}
			elseif (is_array($vars)){
				return (sizeof($vars) <= $value)?true:false;
			}
			else {
				return false;
			}
		}
		else {
			if(preg_match("|^[\d\.]$|Ui", $vars)){
				return ($vars < $value)?true:false;
			}
			elseif (is_string($vars)){
				return (strlen($vars) < $value)?true:false;
			}
			elseif (is_array($vars)){
				return (sizeof($vars) < $value)?true:false;
			}
			return false;
		}		
	}
	/**
	 * �������� ��� �������� ������ ���
	 *
	 * ��������� ������, ����� ��� �����. �� ���� ���������� ������� ������ false
	 *
	 * @param mixed $vars
	 * @param numeric $value
	 * @param boolean $equal
	 * @return boolean
	 */
	static function MoreThan(&$vars, $value, $equal=false){
		
		$value=(int)$value;
		
		if($equal){
			
			
			if(is_numeric($vars)){
				return ($vars >= $value)?true:false;
			}
			elseif (is_string($vars)){
				return (strlen($vars) >= $value)?true:false;
			}
			elseif (is_array($vars)){
				return (sizeof($vars) >= $value)?true:false;
			}
			else {
				return false;
			}
		}
		else {
			
			if(preg_match("|^[\d\.]$|Ui", $vars)){
				return ($vars > $value)?true:false;
			}
			elseif (is_string($vars)){
				return (strlen($vars) > $value)?true:false;
			}
			elseif (is_array($vars)){
				return (sizeof($vars) > $value)?true:false;
			}
			else {
				return false;
			}
		}		
	}
	/**
	 * �������� �� ����������� ���������
	 *
	 * @param string $vars
	 * @param string $regexp
	 * @return boolean
	 */
	static function RegExp(&$vars, $regexp){
		return preg_match($regexp, $vars);
	}
	/**
	 * �������� ��� �������� �������� ������
	 *
	 * @param numeric $vars
	 * @return boolean
	 */
	static function IsNumeric(&$vars){
		
		return is_numeric($vars);
	}
	
	/**
	 * �������� ��� �������� �������� ����� ������
	 *
	 * @param integer $value
	 * @return boolean
	 */
	
	static function IsInt($vars){
		
		if (!is_string($vars) && !is_int($vars) && !is_float($vars)) {
            return false;
        }

        if (is_int($vars)) {
            return true;
        }

        if (strval(intval($vars)) != $vars) {
            return false;
        }

        return true;
	}
	/**
	 * �������� �� URL`��
	 *
	 * @param string $value
	 * @return boolean
	 */
	static function IsURL(&$value){
		
		return preg_match("|^http(s*):\/\/|mUi", $value);
		
	}
	/**
	 * �������� �� email`��
	 *
	 * @param string $value
	 * @return boolean
	 */
	static function IsEmail(&$value){
		
		if ((strpos($value, '..') !== false) || (!preg_match('/^(.+)@([^@\.]+\.+[^@]+)$/', $value))) {
			return false;
        }
		return true;		
	}
	/**
	 * �������� �� ������ ����� ��������� �������.
	 * ������ �� ��������� yyyy-mm-dd
	 * ��������� ��������:<br>
	 * y - �������� 1900 - 2200
	 * m - �������� 1-12
	 * d - �������� 1-31
	 * h - �������� 0-23
	 * i - �������� 0-59
	 * s - �������� 0-59
	 * @param string $value
	 * @param sring with format date $format
	 * @return boolean
	 */
	static function IsDate(&$value, $format='yyyy-mm-dd'){
		
		$format=strtolower($format);
		if(strlen($format)==0)$format='yyyy-mm-dd';
		
		$int_count=0;
		$preg='';
		$prevChar='';
		$formatArr=array('');
		
		for ($i=0; $i<strlen($format)+1; $i++){
			
			$curChar=(isset($format[$i]))?$format[$i]:'';
			
			if($curChar=='y' || $curChar=='m' || $curChar=='d' || $curChar=='h' || $curChar=='i' || $curChar=='s'){
				if($curChar==$prevChar){
					$int_count++;
				}
				else {
					if($int_count > 0)$preg.="(\d{{$int_count}})";
					$formatArr[]=$curChar;
					$int_count=1;
				}
				
			}
			else {
				if($int_count > 0){
					$preg.="(\d{{$int_count}})";
					$int_count=0;
				}
				$preg.=($curChar=='.' || $curChar=='|' ||  $curChar=='(' ||  $curChar==')')?'\\'.$curChar:$curChar;
			}
			
			$prevChar=isset($format[$i])?$format[$i]:'';
			
		}
		$preg="|^{$preg}$|";
		
		if(!preg_match($preg, $value, $found))return false;
		
		foreach ($formatArr as $k=>$dateIntvl){
			if($k==0)continue;
			if($dateIntvl=="y" && ($found[$k] <= 1900 || $found[$k] > 2200))return false;
			if($dateIntvl=="m" && ($found[$k] <= 0 || $found[$k] > 12)) return false;
			if($dateIntvl=="d" && ($found[$k] <= 0 || $found[$k] > 31))return false;
			if($dateIntvl=="h" && ($found[$k] < 0 || $found[$k] > 23))return false;
			if($dateIntvl=="i" && ($found[$k] < 0 || $found[$k] > 59))return false;
			if($dateIntvl=="s" && ($found[$k] < 0 || $found[$k] > 59))return false;
			
		}
		
		return true;
	}
	/**
	 * �������� �� �������� ������
	 *
	 * @param string $value
	 * @return boolean
	 */
	static function NotEmptyTrim(&$value){
		
		if(is_null($value))return false;
		
		if(is_array($value)){
			return (sizeof($value) > 0)?true:false;
		}
		
		if(trim($value)=='')return false;
		return true;		
	}
	/**
	 * ��� ���� �� �������� � ��������, ��� ���� ����� ���� ������
	 * 
	 * ��� ������ ���� ���� ���� �������� ������ ������� ��
	 * �������� ��������� �����������
	 *
	 * @param string $value
	 * @return boolean
	 */
	static function MayBeEmpty(&$value){
		
		return ($value =='')?true:false;		
	}
	/**
	 * ��������� �������� �� ���� �������� ���������
	 *
	 * @param string|array $file path to file|$_FILES['filename']
	 * @param array|false $ext_array.
	 * ���� false - ��� ��������, ���� array - �������� �� ����� �������, ���� �� ������ - �������� �� ���������� �������.
	 * @param array|false $mime_array
	 * ���� false - ��� ��������, ���� array - �������� �� ����� �������, ���� �� ������ ��� true - �������� �� ���������� �������.
	 * �������� ������ ���� ��������� class_exists('finfo')
	 * @param int $width
	 * @param int $height
	 * @param int (bytes) $file_size
	 * @param link $error Set variable last error (extension,width,height,filesize)
	 * 
	 */
	static function IsImage($file, $ext_array=array(), $width=0, $height=0, $file_size = -1, &$error=null){
		
		$error=array();
		
		$return=true;
		
		if($ext_array===true)$ext_array=array();
		if(is_null($file_size))$file_size=-1;
		if(is_null($width))$width=0;
		if(is_null($height))$height=0;
		
		if(is_array($file)){//������ �� $_FILES
			
			if(!array_key_exists('tmp_name', $file) || !array_key_exists('name', $file)){
				throw new Exception("Array must by \$_FILES");
			}
			$filepath = $file['tmp_name'];
			$filename = $file['name'];
		}
		else {
			$filepath = $filename = $file;
		}
		
		if(!file_exists($filepath)){
			$error[] = (isset(FormValidator::$valid_labels['IsImageInternal']['file_not_found']))?FormValidator::$valid_labels['IsImageInternal']['file_not_found']:"file_not_found";
			$return=false;
		}
		
        $default_extension=array(
        	'gif',
        	'png',
        	'jpg',
        	'jpeg',
        	'JPEG',
        	'bmp',
        	'tiff',
        	'ico'
        );
        
        if($ext_array!==false && sizeof($ext_array) == 0){
        	$ext_array=$default_extension;
        }
                
        if($file_size >= 0 && (filesize($filepath)===false || filesize($filepath) > $file_size)){
        	$error[] =(isset(FormValidator::$valid_labels['IsImageInternal']['filesize']))?FormValidator::$valid_labels['IsImageInternal']['filesize']:"filesize";
        	$return=false;
        }
        
        $info = false;
        
        if($filepath != ''){
        	$info=getimagesize($filepath);
        }
        if($info===false){
        	$error[]=(isset(FormValidator::$valid_labels['IsImageInternal']['notimg']))?FormValidator::$valid_labels['IsImageInternal']['notimg']:"notimg";
        	$return=false;
        }
        
        if($width!=0 && $info[0] > $width){
        	$error[]=(isset(FormValidator::$valid_labels['IsImageIsImageInternal']['width']))?FormValidator::$valid_labels['IsImageInternal']['width']:"width";
        	$return=false;
        }
        if($height!=0 && $info[1] > $height){
        	$error[]=(isset(FormValidator::$valid_labels['IsImageInternal']['height']))?FormValidator::$valid_labels['IsImageInternal']['height']:"height";
        	$return=false;
        }
        
        if(is_array($ext_array)){
        	$found=false;
        	foreach ($ext_array as $ext_e){
        		$ext=strtolower(substr($filename, (strlen($ext_e)+1)*-1));
        		if($ext=='.'.$ext_e)$found=true;		
        	}
        	
        	if(!$found){
        		$error[]=(isset(FormValidator::$valid_labels['IsImageInternal']['extension']))?FormValidator::$valid_labels['IsImageInternal']['extension']:"extension";
        		$return=false;        	
        	}
        }
        
        return $return;        
	}
	
	/**
	 * ��������� �������� �� ���� �������� ���������
	 *
	 * @param string|array $file path to file|$_FILES['filename']
	 * @param array|false $ext_array.
	 * ���� false - ��� ��������, ���� array - �������� �� ����� �������, ���� �� ������ - �������� �� ���������� �������.
	 * @param array|false $mime_array
	 * ���� false - ��� ��������, ���� array - �������� �� ����� �������, ���� �� ������ ��� true - �������� �� ���������� �������.
	 * �������� ������ ���� ��������� class_exists('finfo')
	 * @param int $width
	 * @param int $height
	 * @param int (bytes) $file_size
	 * @param link $error Set variable last error (extension,width,height,filesize)
	 * 
	 */
	static function IsImageAutosave($file, $ext_array=array(), $width=0, $height=0, $file_size = -1, &$error=null){
		
		$error=array();
		
		$return=true;
		
		if($ext_array===true)$ext_array=array();
		if(is_null($file_size))$file_size=-1;
		if(is_null($width))$width=0;
		if(is_null($height))$height=0;
		
		if(is_array($file)){//������ �� $_FILES
			
			if(!array_key_exists('tmp_name', $file) || !array_key_exists('name', $file)){
				throw new Exception("Array must by \$_FILES");
			}
			$filepath = $file['tmp_name'];
			$filename = $file['name'];
		}
		else {
			$filepath = $filename = $file;
		}
		
		if(!file_exists($filepath)){
			$error[] = (isset(FormValidator::$valid_labels['IsImageInternal']['file_not_found']))?FormValidator::$valid_labels['IsImageInternal']['file_not_found']:"file_not_found";
			$return=false;
		}
		
        $default_extension=array(
        	'gif',
        	'png',
        	'jpg',
        	'jpeg',
        	'bmp',
        	'tiff',
        	'ico'
        );
        
        if($ext_array!==false && sizeof($ext_array) == 0){
        	$ext_array=$default_extension;
        }
                
        if($file_size >= 0 && (filesize($filepath)===false || filesize($filepath) > $file_size)){
        	$error[] =(isset(FormValidator::$valid_labels['IsImageInternal']['filesize']))?FormValidator::$valid_labels['IsImageInternal']['filesize']:"filesize";
        	$return=false;
        }
        
        $info = false;
        
        if($filepath != ''){
        	$info=getimagesize($filepath);
        }
        if($info===false){
        	$error[]=(isset(FormValidator::$valid_labels['IsImageInternal']['notimg']))?FormValidator::$valid_labels['IsImageInternal']['notimg']:"notimg";
        	$return=false;
        }
        
        if($width!=0 && $info[0] > $width){
        	$error[]=(isset(FormValidator::$valid_labels['IsImageIsImageInternal']['width']))?FormValidator::$valid_labels['IsImageInternal']['width']:"width";
        	$return=false;
        }
        if($height!=0 && $info[1] > $height){
        	$error[]=(isset(FormValidator::$valid_labels['IsImageInternal']['height']))?FormValidator::$valid_labels['IsImageInternal']['height']:"height";
        	$return=false;
        }
        
        if(is_array($ext_array)){
        	$found=false;
        	foreach ($ext_array as $ext_e){
        		$ext=strtolower(substr($filename, (strlen($ext_e)+1)*-1));
        		if($ext=='.'.$ext_e)$found=true;		
        	}
        	
        	if(!$found){
        		$error[]=(isset(FormValidator::$valid_labels['IsImageInternal']['extension']))?FormValidator::$valid_labels['IsImageInternal']['extension']:"extension";
        		$return=false;        	
        	}
        }
        
        return $return;        
	}
	
	/**
	 * ��������� �������� �� ���� �������� �� ����������
	 *
	 * @param string|array $file path to file|$_FILES['filename']
	 * @param array|false $ext_array.
	 * ���� false - ��� ��������, ���� array - �������� �� ����� �������, ���� �� ������ - �������� �� ���������� �������.
	 * @param array|false $mime_array
	 * ���� false - ��� ��������, ���� array - �������� �� ����� �������, ���� �� ������ ��� true - �������� �� ���������� �������.
	 * �������� ������ ���� ��������� class_exists('finfo')
	 * @param int (bytes) $file_size
	 * @param link $error Set variable last error (extension,width,height,filesize)
	 * 
	 */
	static function IsFile($file, $ext_array=array(), $file_size = -1, &$error=null){
		
		$error=array();
		
		$return=true;
		
		if($ext_array===true)$ext_array=array();
		if(is_null($file_size))$file_size=-1;
		
		if(is_array($file)){//������ �� $_FILES
			
			if(!array_key_exists('tmp_name', $file) || !array_key_exists('name', $file)){
				throw new Exception("Array must by \$_FILES");
			}
			$filepath = $file['tmp_name'];
			$filename = $file['name'];
		}
		else {
			$filepath = $filename = $file;
		}
		
		if(!file_exists($filepath)){
			$error[] = (isset(FormValidator::$valid_labels['IsFileInternal']['file_not_found']))?FormValidator::$valid_labels['IsFileInternal']['file_not_found']:"file_not_found";
			$return=false;
		}
		
        $default_extension=array(
        	'xls',
        	'doc',
        	'xlsx',
        	'docx',
        	'rar',
        	'zip',
        	'7zip',
        	'ppt',
        	'pptx',
        	'gif',
        	'png',
        	'jpg',
        	'bmp',
        	'tiff',
        	'ico'
        );
        
        if($ext_array!==false && sizeof($ext_array) == 0){
        	$ext_array=$default_extension;
        }
                
        if($file_size >= 0 && (filesize($filepath)===false || filesize($filepath) > $file_size)){
        	$error[]=(isset(FormValidator::$valid_labels['IsFileInternal']['filesize']))?FormValidator::$valid_labels['IsFileInternal']['filesize']:"filesize";
        	$return=false;
        }
        
        if(is_array($ext_array)){
        	$found=false;
        	foreach ($ext_array as $ext_e){
        		$ext=strtolower(substr($filename, (strlen($ext_e)+1)*-1));
        		if($ext=='.'.$ext_e)$found=true;		
        	}
        	
        	if(!$found){

        		$error[]=(isset(FormValidator::$valid_labels['IsFileInternal']['extension']))?FormValidator::$valid_labels['IsFileInternal']['extension']:"extension";
        		$return=false;        	
        	}
        }
        
        return $return;        
	}
	
	/**
	 * ��������� ������� ����������� ���������� � ��������� �� ������ � ����
	 *
	 * @param string $label
	 * @param array|mixed $values
	 * @return string
	 */
	protected function _ParseLabel($label, $values){
		if(is_array($values)){
			$arr=array();
			
			for ($i=0; $i<sizeof($values); $i++){
				$arr['{'.$i.'}']=$values[$i];
			}
		}
		else {
			$arr['{0}']=$values;
		}
		return strtr($label,
			$arr
			);
		
	}
	
}